home *** CD-ROM | disk | FTP | other *** search
- /* shadow.c
- * Part of the Moon application for the NeXT computer.
- * Author: Geoffrey S. Knauth
- * Date: January 4, 1992
- *
- * Permission to copy this program is hereby granted under the terms
- * of the Free Software Foundation's GNU General Public License.
- */
-
- #import <dpsclient/event.h> /* NXPoint */
- #import <dpsclient/psops.h> /* PSsetgray */
- #import "all.h"
-
- void DrawMoonShadow /* draw moon shadow, independent of view */
- (float phase, /* phase of the moon */
- NXPoint *center, /* pixel center of moon */
- float xradius, /* half width of moon in pixels */
- float yradius, /* half height of moon in pixels */
- int shadowColor) /* color to use in drawing shadow */
- {
- /* DrawMoonShadow is called from within drawSelf:: methods of various
- * view types. Postscript focus locking and unlocking are outside
- * of this function.
- */
- float yDown, yUp;
- int i, up, down, oneSideHalf, numLeftSidePoints, numRightSidePoints;
- NXPoint *leftSide, *rightSide; /* storage for lists of NXPoints */
- double d, amp, xscale;
-
- /* the number of points in the top half on one side is
- * oneSideHalf = center+1..top,
- * = (top - (center+1) + 1), or (top - center);
- */
- oneSideHalf = rint(yradius);
-
- /* make sure oneSideHalf is >= 0 */
- if (oneSideHalf < 0) oneSideHalf = 0;
-
- /* calculate the number of points on each side
- * remember to add a point for the center
- */
- numLeftSidePoints = numRightSidePoints = 1 + 2 * oneSideHalf;
-
- /* allocate the points */
- leftSide = calloc(numLeftSidePoints, sizeof(NXPoint));
- rightSide = calloc(numRightSidePoints, sizeof(NXPoint));
-
- /* Now iterate from the center to the bottom, filling in information
- * for the left and right sides.
- * Remember to calculate the region to black out, not whiten.
- * As we fill in points for the bottom half, we know that the points
- * for the top half will be a mirror image, so we can just copy them.
- */
- xscale = cos(2 * PI * phase);
- for (i = 0, /* variable controlling loop */
- down = oneSideHalf, /* index into arrays of NXPoint */
- yDown = yUp = center->y; /* diverging y values for halves */
- i <= oneSideHalf; /* stop when bottom half done */
- i++, /* 0..oneSideHalf-1 */
- down++, /* oneSideHalf..bottom index */
- yDown -= 1., /* float y for drawing bottom half */
- yUp += 1.) /* float y for drawing upper half */
- {
- if ((d = i / yradius) > 1.0)
- d = 1.0;
- amp = xradius * cos(asin(d)); /* d > 1.0 yields NaN (not a number) */
-
- /* 0.0 = new moon, 0.5 full moon, 1.0 = next new moon */
- if (phase < 0.5) { /* waxing */
- leftSide[down].x = center->x - amp;
- rightSide[down].x = center->x + xscale * amp;
- } else { /* waning */
- rightSide[down].x = center->x + amp;
- leftSide[down].x = center->x - xscale * amp;
- }
- leftSide[down].y = rightSide[down].y = yDown;
-
- if (i) { /* # points offset downward from center */
- up = down - 2 * i;
- leftSide[up].x = leftSide[down].x;
- rightSide[up].x = rightSide[down].x;
- leftSide[up].y = rightSide[up].y = yUp;
- }
- }
-
- /* Now iterate again from the top, this time actually creating
- * a path clockwise around the points just calculated.
- */
- PSnewpath();
- PSmoveto(rightSide[0].x, rightSide[0].y);
-
- /* Go down the right side, starting with the second point, because we
- * just moved to the top point.
- */
- for (i = 1; i < numRightSidePoints; i++)
- PSlineto(rightSide[i].x, rightSide[i].y);
-
- /* Now go up the left side, starting again with the second point, because
- * we just reached the bottom, and stop one short of the top, because we
- * started with the top when we started down in the first place.
- */
- for (i = numLeftSidePoints - 2; i > 0; i--)
- PSlineto(leftSide[i].x, leftSide[i].y);
-
- PSclosepath();
-
- /* draw the moon shadow, that part of the moon hidden from the sun */
- PSsetgray(shadowColor);
- PSfill();
-
- /* deallocate the points */
- free((char *) leftSide);
- free((char *) rightSide);
- }
-
-